home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Disc to the Future 2
/
Disc to the Future Part II Programmer's Reference (Wayzata Technology)(6013)(1992).bin
/
MAC
/
THINKC
/
TCL1
/
GRAPH_FO
/
(GRAPH
/
GRAPH_SO
/
GRAPH.C
next >
Wrap
Text File
|
1991-04-09
|
9KB
|
403 lines
/******************************************************************************
Graph.c
Graph methods in Object C.
SUPERCLASS = CObject
Copyright ⌐ 1991 Maarten Meijer. All rights reserved.
CIS 100016,1764; FidoNet 2:512/114
*******************************************************************************/
/* includes */
#include <CError.h>
#include "GraphCommands.h"
#include "Graph.h"
#include "CLinkTask.h"
#include "CSelRectTask.h"
#include "CMoveTask.h"
/* externs */
extern CError *gError;
/* methods */
/******************************************************************************
IGraph
Initialize a graph structure,
thePane : the enclosing Panorama/Pane
flags : should be used to determine :
Ñ undirected vs. directed graph
Ñ single vs multigraph
Ñ weighed edges (also select edges)
Ñ vert. and hor. alignment
grid : the grid size as Point
*******************************************************************************/
void
Graph::IGraph(CPanorama *thePane, short flags, Point grid) {
vertexList = (GrList *)new(GrList);
vertexList->IGrList();
edgeList = (GrList *)new(GrList);
edgeList->IGrList();
_grid = grid;
_flags = flags;
itsPane = thePane;
}
/******************************************************************************
Dispose
*******************************************************************************/
void
Graph::Dispose() {
edgeList->DisposeAll(); /* CCluster */
vertexList->DisposeAll(); /* CCluster */
inherited::Dispose(); /* CObject */
}
Point
Graph::Align(Point pt) {
Point new;
new = pt;
if(_grid.h && (_flags & grHAlign))
new.h = (pt.h / _grid.h) * _grid.h + (_grid.h >> 1); /* align to grid */
if(_grid.v && (_flags & grVAlign))
new.v = (pt.v / _grid.v) * _grid.v + (_grid.v >> 1);
return new;
}
/******************************************************************************
Draw
Draw the area in the rectangle area. This could probably look better
if drawing was into an offscreen bitmap, and the copy into the pane.
*******************************************************************************/
void
Graph::Draw(Rect *area) {
long finalTicks;
if(_flags & grDebug) {
PenPat(gray);
PaintRect(area);
PenNormal();
Delay(60, &finalTicks);
}
EraseRect(area);
edgeList->Draw(area);
vertexList->Draw(area);
}
/******************************************************************************
NewVertex
Create a new vertex, makes it easier to override the creation of
vertices.
*******************************************************************************/
GrVertex *
Graph::NewVertex() {
register GrVertex *vertex;
vertex = (GrVertex *)new(GrVertex);
vertex->IGraphNode();
return vertex;
}
/******************************************************************************
newEdge
Create a new edge, makes it easier to override the creation of edges.
*******************************************************************************/
GrEdge *
Graph::NewEdge() {
register GrEdge *edge;
edge = (GrEdge *)new(GrEdge);
edge->IGraphNode();
return edge;
}
/******************************************************************************
AddVertex
Create vertex and add to the vertexlist.
*******************************************************************************/
GrVertex *
Graph::AddVertex(Point center, Boolean redraw) {
GrVertex * newVertex;
newVertex = NewVertex();
vertexList->AddNode((GrNode *)newVertex);
newVertex->SetCenter(Align(center));
return (newVertex);
}
void
Graph::RemoveVertex(GrVertex *whichVertex, Boolean redraw) {
GrEdge * whichEdge;
Rect area, rect;
Point ctr;
if(whichVertex == (GrNode *)NULL)
return;
if(redraw)
whichVertex->GetRect(&area);
do {
whichEdge = (GrEdge *)edgeList->FindIncident(whichVertex);
if(whichEdge != (GrEdge *)NULL) {
if(redraw) {
whichEdge->GetRect(&rect);
UnionRect(&rect, &area, &area);
}
edgeList->RemoveNode(whichEdge);
}
} while(whichEdge != (GrEdge *)NULL);
vertexList->RemoveNode(whichVertex);
if(redraw)
itsPane->RefreshRect(&area);
}
GrEdge *
Graph::AddEdge(GrVertex *from, GrVertex *to, Boolean redraw) {
Rect area;
GrEdge * newEdge;
if( ( !(_flags & grSelfRef) ) &&
( from == to ) ) {
gError->PostAlert(grErrID, grNoSelfErr);
return NULL;
}
if((_flags & grMulti) == 0) {
if(_flags & grDirected) { /* Check first if it is allready there */
if(AdjacentTo(from, to)) {
gError->PostAlert(grErrID, grMultiErr);
return NULL;
}
}
else {
if(Adjacent(from, to)) {
gError->PostAlert(grErrID, grMultiErr);
return NULL;
}
}
}
newEdge = NewEdge();
newEdge->SetFrom(from);
newEdge->SetTo(to);
edgeList->AddNode((GrNode *)newEdge);
if(redraw) {
newEdge->GetRect(&area);
itsPane->RefreshRect(&area);
}
return(newEdge);
}
void
Graph::RemoveEdge(GrEdge * whichEdge, Boolean redraw) {
Rect area;
if(whichEdge != (GrEdge *)NULL) {
if(redraw)
whichEdge->GetRect(&area);
edgeList->RemoveNode(whichEdge);
if(redraw)
itsPane->RefreshRect(&area);
}
}
void
Graph::SetVertexCenter(GrVertex *which, Point where, Boolean redraw) {
Rect area;
if(redraw) {
edgeList->SpanningRect(which, &area);
itsPane->RefreshRect(&area);
}
which->SetCenter(Align(where));
if(redraw) {
edgeList->SpanningRect(which, &area);
itsPane->RefreshRect(&area);
}
}
/******************************************************************************
Deselect
Deselect all vertices and edges in the graph.
*******************************************************************************/
void
Graph::Deselect() {
vertexList->Deselect();
edgeList->Deselect();
}
void
Graph::GetGrid(Point *grid) {
*grid = _grid;
}
GrVertex *
Graph::FindVertex(Point where) {
return (GrVertex *)vertexList->FindNode(where);
}
GrEdge *
Graph::FindEdge(Point where) {
return (GrEdge *)edgeList->FindNode(where);
}
/******************************************************************************
Testing for adjacency of two vertices
(This should depend on MultiGraph/DiGraph flags, but does not for
the moment)
suppose: v1 ----> v2
AdjacentTo(v1,v2) returns TRUE (if digraph)
AdjacentFrom(v1,v2) returns FALSE (if digraph)
Adjacent(v1,v2) returns TRUE (if not digraph)
*******************************************************************************/
static GrVertex *tv1, *tv2;
static Boolean
_AdjacentTo(GrEdge *edge) {
return( (tv1 == edge->fromVertex) &&
(tv2 == edge->toVertex ) );
}
Boolean
Graph::AdjacentTo(GrVertex *v1, GrVertex *v2) {
tv1 = v1;
tv2 = v2;
return(edgeList->FindItem(_AdjacentTo) != NULL);
}
Boolean
Graph::AdjacentFrom(GrVertex *v1, GrVertex *v2) {
tv1 = v2;
tv2 = v1;
return(edgeList->FindItem(_AdjacentTo) != NULL);
}
Boolean
Graph::Adjacent(GrVertex *v1, GrVertex *v2) {
return ( AdjacentTo(v1, v2) || AdjacentFrom(v1, v2) );
}
/******************************************************************************
SetOptions
Set the options for demo purposes with a dialog.
*******************************************************************************/
static pascal Boolean
numkeyfilter(DialogPtr dlg, EventRecord *evt, short *itemHit) {
char temp;
if( ((evt->what == keyDown) || (evt->what == autoKey)) ) {
temp = evt->message & charCodeMask;
if(temp >= '0' && temp <= '9') {
return false;
}
else if(temp == '\t' || temp == 8) {
return false;
}
else if(temp == 3 || temp == '\r') {
*itemHit = ITEMcancel;
return true;
}
else {
SysBeep(2);
return true;
}
}
return false;
}
void
Graph::SetOptions() {
DialogPtr dlg;
short itemHit, kind;
register short item, value, newflags;
Handle h;
Rect r;
ControlHandle CItem;
long number;
Str255 numStr;
dlg = GetNewDialog(DLOGoptions, NULL, (WindowPtr)(-1));
SetOutlineButton(dlg, ITEMcancel, ITEMoutline);
SelIText(dlg, ITEMhgrid, 0, 32767);
ShowWindow((WindowPtr)dlg);
SetPort((GrafPtr)dlg);
for(item = ITEMhalign; item <= ITEMdebug; ++item) {
if(_flags & (1 << (item - ITEMhalign)))
value = 1;
else
value = 0;
GetDItem(dlg, item, &kind, &h, &r);
CItem = (ControlHandle)h;
SetCtlValue(CItem, value);
}
NumToString((long)_grid.h, numStr);
GetDItem(dlg, ITEMhgrid, &kind, &h, &r);
SetIText(h, numStr);
NumToString((long)_grid.v, numStr);
GetDItem(dlg, ITEMvgrid, &kind, &h, &r);
SetIText(h, numStr);
do {
ModalDialog(numkeyfilter, &itemHit);
switch(itemHit) {
case ITEMhalign:
case ITEMvalign:
case ITEMdigraph:
case ITEMmulti:
case ITEMdebug:
case ITEMselfref:
GetDItem(dlg, itemHit, &kind, &h, &r);
CItem = (ControlHandle)h;
value = GetCtlValue(CItem);
SetCtlValue(CItem, ((value + 1) & 1));
break;
}
} while ( (itemHit != ITEMok) && (itemHit != ITEMcancel) );
if(itemHit == ITEMok) {
newflags = 0;
for(item = ITEMhalign; item <= ITEMdebug; ++item) {
GetDItem(dlg, item, &kind, &h, &r);
CItem = (ControlHandle)h;
value = GetCtlValue(CItem);
newflags |= (value << (item - ITEMhalign));
}
_flags = newflags;
GetDItem(dlg, ITEMhgrid, &kind, &h, &r);
GetIText(h, numStr);
StringToNum(numStr, &number);
if(number < 300)
_grid.h = (short)number;
GetDItem(dlg, ITEMvgrid, &kind, &h, &r);
GetIText(h, numStr);
StringToNum(numStr, &number);
if(number < 300)
_grid.v = (short)number;
}
DisposDialog(dlg);
}